<!--
* @author: lzm
* @date: 2023年11月27日10:52:10
* @description：人员管理新增/编辑弹窗
* @update: 2023年11月27日10:52:16
-->
<template>
  <div>
    <el-dialog
      :title="title"
      :visible="showDialog"
      width="600px"
      center
      custom-class="my-dialog form-top"
      @close="closeFn"
    >
      <el-form
        ref="ruleForm"
        label-width="120px"
        :model="addList"
        :rules="rules"
      >
        <el-form-item label="归属部门" prop="dept">
          <el-input
            v-model.trim="addList.dept"
            placeholder="请输入"
            style="width: 97%"
            size="small"
          />
        </el-form-item>
        <el-form-item label="人员姓名" prop="nickName">
          <el-input
            v-model.trim="addList.nickName"
            placeholder="请输入"
            style="width: 97%"
            size="small"
          />
        </el-form-item>
        <el-form-item label="账号" prop="username">
          <el-input
            v-model.trim="addList.username"
            placeholder="请输入"
            style="width: 97%"
            size="small"
          >
          </el-input>
        </el-form-item>
        <el-form-item label="密码" class="password">
          <el-input
            v-model.trim="addList.newPassword"
            placeholder="请输入"
            style="width: 97%"
            size="small"
          >
          </el-input>
        </el-form-item>
        <el-form-item label="照片" class="photo">
          <el-button size="small" type="primary" @click="openCamera">拍照</el-button>
          <input type="file" ref="fileInput" style="display: none" accept="image/*" @change="handleImageUpload" />
          <img v-if="addList.photoData" :src="addList.photoData" alt="预览" style="width: 100px; height: 100px; margin-top: 10px;" />
        </el-form-item>

        <!-- 按钮 -->
        <el-row type="flex" justify="center">
          <el-col :span="12">
            <el-button
              class="dialog-btn"
              size="mini"
              type="primary"
              @click="addBtn"
            >
              确认
            </el-button>
            <!-- <el-button size="mini" @click="closeFn">取消</el-button> -->
          </el-col>
        </el-row>
      </el-form>
    </el-dialog>

    <!-- 修改后的摄像头预览对话框 -->
    <el-dialog
      title="摄像头预览"
      :visible.sync="cameraDialogVisible"
      width="80%"
      @close="closeCameraDialog"
      :close-on-click-modal="false"
      destroy-on-close
    >
      <div>
        <!-- 加载指示器 -->
        <div v-if="isVideoLoading" class="loading-indicator">
          <i class="el-icon-loading"></i>
          <span>正在连接摄像头...</span>
        </div>

        <!-- 视频流显示 - 使用img标签显示来自SSE的视频帧 -->
        <div v-if="!isVideoLoading" class="video-container">
          <img
            v-if="videoSrc"
            :src="videoSrc"
            alt="摄像头画面"
            class="video-frame"
            @error="handleVideoError"
          />

          <!-- 无视频流时的占位符 -->
          <div v-if="!videoSrc" class="no-video-placeholder">
            <i class="el-icon-video-camera"></i>
            <p>等待视频流...</p>
          </div>
        </div>

        <!-- 预览图像（拍照后显示） -->
        <img v-if="previewSrc" :src="previewSrc" alt="预览图像" style="max-width: 100%; height: auto; margin-top: 10px;" />

        <!-- 隐藏的canvas元素，用于图片处理 -->
        <canvas ref="canvas" style="display: none;"></canvas>

        <!-- 操作按钮 -->
        <div class="camera-controls">
          <el-button @click="confirmCapture" type="primary" :disabled="!videoSrc">确认拍照</el-button>
          <el-button @click="closeCameraDialog">关闭</el-button>
        </div>
      </div>
    </el-dialog>

    <!-- 新增成功后提示弹窗 -->
    <el-dialog
      title="温馨提示"
      :visible.sync="addPromptSync"
      :close-on-click-modal="false"
      width="536px"
      custom-class="my-dialog prompt-dialog"
      center
    >
      <span>新增成功，请通过账号密码进行登录或前往门禁设备上进行人脸录入</span>
    </el-dialog>
  </div>
</template>

<script>
import {
  addPersonnelList,
  getPersonnelDetail,
  editPersonnelDetail
} from '@/api/personnelManage'
import md5 from 'js-md5'
import request from '@/utils/request'
import { setCountdown, setIsAdmin, setLogin, setToken } from '@/utils/auth'

export default {
  props: {
    showDialog: {
      type: Boolean,
      default: false
    },
    title: String,
    id: [Number, String]
  },

  data() {
    return {
      addList: {
        dept: '', // 操作人部门
        nickName: '', // 操作人姓名
        username: '', // 账号
        newPassword: '', // 密码
        photoData: '' // 定义 photo 属性
      },
      rules: {
        dept: [
          {
            required: true, // 必填项
            message: '操作人部门不能为空', // 未通过校验的提示信息
            trigger: ['blur', 'change'] // 校验触发时机
          },
          {
            min: 1,
            max: 50,
            message: '部门输入长度过长！',
            trigger: 'blur'
          }
        ],
        nickName: [
          {
            required: true,
            message: '操作人姓名不能为空',
            trigger: 'blur'
          },
          {
            min: 1,
            max: 50,
            message: '姓名输入长度过长！',
            trigger: 'blur'
          }
        ],
        username: [
          {
            required: true,
            message: '账号不能为空',
            trigger: ['blur', 'change']
          },
          {
            min: 1,
            max: 50,
            message: '账号输入长度过长！',
            trigger: 'blur'
          }
        ]
      },
      addPromptSync: false,
      cameraDialogVisible: false,
      previewSrc: null, // 存储预览图像数据

      // 新增SSE相关属性
      sseConnection: null, // SSE连接
      videoSrc: '', // 当前视频帧的src
      isVideoLoading: false, // 视频加载状态
      currentVideoFrame: null, // 当前视频帧数据，用于拍照

      // 新增：保存拍照时的canvas引用
      capturedCanvas: null,
    }
  },
  computed: {
    bgColor() {
      return this.$store.state.settings.theme
    }
  },
  watch: {
    id: {
      async handler(val) {
        if (val != null) {
          const { result } = await getPersonnelDetail(val)
          this.addList = result
        }
      }
    }
  },
  methods: {
    // 关闭弹窗清空所有值
    closeFn() {
      this.$emit('update:showDialog', false)
      this.$emit('update:id', null)
      this.$emit('clearFn')
      this.$refs.ruleForm.resetFields()

      // 清理canvas引用
      this.capturedCanvas = null

      this.addList = {
        dept: '',
        nickName: '',
        username: '',
        newPassword: '',
        photoData: '' // 添加 photo 属性用于图片预览
      }
    },

    // 修改addBtn方法，确保获取到用户ID后再上传照片
    async addBtn() {
      this.$refs.ruleForm.validate(async (valid) => {
        if (valid) {
          let response;

          if (this.addList.id) {
            // 编辑现有用户
            if(!this.addList.newPassword){
              response = await editPersonnelDetail({
                id: this.addList.id,
                dept: this.addList.dept,
                nickName: this.addList.nickName,
                username: this.addList.username,
                imageBase: this.addList.photoData
              })
            } else {
              if(this.addList.newPassword.length < 6 || this.addList.newPassword.length > 16){
                this.$message.error('密码长度应为6-16位之间')
                return
              }
              response = await editPersonnelDetail({
                id: this.addList.id,
                dept: this.addList.dept,
                nickName: this.addList.nickName,
                username: this.addList.username,
                newPassword: md5(this.addList.newPassword),
                imageBase: this.addList.photoData
              })
            }
            this.$message.success('修改成功！')

            // 如果有照片，上传照片
            if (this.addList.photoData && (this.capturedCanvas || this.$refs.canvas)) {
              try {
                await this.uploadPhoto(this.addList.id);
                console.log('照片上传完成');
              } catch (error) {
                console.error('照片上传失败:', error);
                this.$message.warning('用户信息保存成功，但照片上传失败');
              }
            }
          } else {
            // 新增用户
            if(this.addList.newPassword == ''){
              response = await addPersonnelList({
                dept: this.addList.dept,
                nickName: this.addList.nickName,
                username: this.addList.username,
                imageBase: this.addList.photoData
              })
            } else {
              if(this.addList.newPassword.length < 6 || this.addList.newPassword.length > 16){
                this.$message.error('密码长度应为6-16位之间')
                return
              }
              response = await addPersonnelList({
                dept: this.addList.dept,
                nickName: this.addList.nickName,
                username: this.addList.username,
                newPassword: md5(this.addList.newPassword),
                imageBase: this.addList.photoData
              })
            }

            // 如果有照片且接口返回了新增用户的ID，上传照片
            if (response && response.result && response.result.id &&
              this.addList.photoData && (this.capturedCanvas || this.$refs.canvas)) {
              try {
                await this.uploadPhoto(response.result.id);
                console.log('照片上传完成');
              } catch (error) {
                console.error('照片上传失败:', error);
                this.$message.warning('用户创建成功，但照片上传失败');
              }
            }

            this.$message.success('新增成功！')
          }

          // 通知父组件重新请求部门列表数据
          this.$emit('updateList')
          this.$emit('update:showDialog', false)
        }
      })
    },

    // 修复后的uploadPhoto方法
    async uploadPhoto(userId) {
      if (!userId) {
        console.error('用户ID为空');
        return;
      }

      // 优先使用保存的canvas引用
      const canvas = this.capturedCanvas || this.$refs.canvas;

      if (!canvas) {
        console.error('Canvas引用不存在');
        this.$message.error('照片数据丢失，请重新拍照');
        return;
      }

      // 验证canvas内容
      const context = canvas.getContext('2d');
      const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
      const isBlank = imageData.data.every(pixel => pixel === 0);

      if (isBlank) {
        console.error('Canvas内容为空');
        this.$message.error('照片内容为空，请重新拍照');
        return;
      }

      return new Promise((resolve, reject) => {
        canvas.toBlob(async (blob) => {
          if (!blob) {
            console.error('无法生成图片blob');
            reject(new Error('无法生成图片数据'));
            return;
          }

          console.log('生成的blob大小:', blob.size, 'bytes');

          const formData = new FormData();
          formData.append('photoData', blob, userId + '.jpg');
          formData.append('userId', userId);

          try {
            const response = await request({
              url: '/userInfo/uploadPhoto',
              method: 'post',
              data: formData,
              headers: {
                'Content-Type': 'multipart/form-data'
              }
            });

            console.log('照片上传成功');
            resolve(response);
          } catch (error) {
            console.error('照片上传失败:', error);
            reject(error);
          }
        }, 'image/jpeg', 0.8); // 添加质量参数
      });
    },

    handleImageUpload(event) {
      const file = event.target.files[0];
      if (file) {
        const reader = new FileReader();
        reader.onload = (e) => {
          this.addList.photoData = e.target.result; // 更新 addList.photo
        };
        reader.readAsDataURL(file);
      }
    },

    // 修改后的打开摄像头方法
    async openCamera() {
      try {
        console.log('开始打开摄像头...');
        this.cameraDialogVisible = true;
        this.isVideoLoading = true;
        this.videoSrc = '';
        this.previewSrc = null;
        this.currentVideoFrame = null;

        // 等待对话框渲染完成
        await this.$nextTick();

        // 延迟一点时间确保对话框完全显示
        setTimeout(() => {
          this.createSSEConnection();
        }, 300);
      } catch (err) {
        this.$message.error('无法访问摄像头');
        console.error('Error accessing camera:', err);
        this.cameraDialogVisible = false;
      }
    },

    // 新增：创建SSE连接方法
    createSSEConnection() {
      // 关闭之前的连接
      this.closeSSEConnection();

      try {
        console.log('正在创建SSE连接...');

        // 获取baseURL - 适配不同的axios配置方式
        let baseUrl = '';

        // 尝试从request工具获取baseURL
        if (request && request.defaults && request.defaults.baseURL) {
          baseUrl = request.defaults.baseURL;
        }
        // 尝试从this.$http获取baseURL
        else if (this.$http && this.$http.defaults && this.$http.defaults.baseURL) {
          baseUrl = this.$http.defaults.baseURL;
        }
        // 尝试从this.axios获取baseURL
        else if (this.axios && this.axios.defaults && this.axios.defaults.baseURL) {
          baseUrl = this.axios.defaults.baseURL;
        }

        // 如果baseURL以/结尾，去掉结尾的/
        if (baseUrl && baseUrl.endsWith('/')) {
          baseUrl = baseUrl.slice(0, -1);
        }

        // 如果没有配置baseURL，则使用当前页面URL
        if (!baseUrl) {
          const protocol = window.location.protocol;
          const host = window.location.host;
          baseUrl = `${protocol}//${host}`;
        }

        // 创建SSE连接，只获取视频流，不启用人脸识别
        const url = `${baseUrl}/baiduFace/startVideoStream?cameraId=0&enableFaceRecognition=false`;
        console.log('SSE连接URL:', url);
        this.sseConnection = new EventSource(url);

        // 连接成功事件
        this.sseConnection.onopen = () => {
          console.log('SSE连接已建立');
        };

        // 监听视频帧事件
        this.sseConnection.addEventListener('videoFrame', (event) => {
          try {
            const data = JSON.parse(event.data);
            if (data && data.imageData) {
              this.displayVideoFrame(data.imageData);
            } else {
              console.warn('视频帧数据格式不正确', data);
            }
          } catch (error) {
            console.error('处理视频帧失败:', error);
          }
        });

        // 监听消息事件
        this.sseConnection.addEventListener('message', (event) => {
          try {
            const data = JSON.parse(event.data);
            console.log('收到SSE消息:', data);

            if (data.type === 'videoStarted') {
              this.isVideoLoading = false;
              console.log('视频流已启动');
            } else if (data.type === 'error') {
              this.$message.error(data.message || '视频流错误');
              this.isVideoLoading = false;
            }
          } catch (error) {
            console.error('处理SSE消息失败:', error);
          }
        });

        // 错误处理
        this.sseConnection.onerror = (error) => {
          console.error('SSE连接错误:', error);
          this.$message.error('视频流连接失败，请重试');
          this.isVideoLoading = false;
          this.closeSSEConnection();
        };

        // 设置5秒超时，如果没有收到视频流则认为连接失败
        setTimeout(() => {
          if (this.isVideoLoading) {
            console.warn('视频流连接超时');
            this.$message.warning('摄像头连接超时，请检查设备状态');
            this.isVideoLoading = false;
          }
        }, 5000);

      } catch (error) {
        console.error('创建SSE连接失败:', error);
        this.$message.error('无法连接到摄像头服务');
        this.isVideoLoading = false;
      }
    },

    // 新增：显示视频帧方法
    displayVideoFrame(imageData) {
      try {
        // 确保是完整的data URL
        let src = '';
        if (typeof imageData === 'string') {
          if (imageData.startsWith('data:image')) {
            src = imageData;
          } else {
            src = 'data:image/jpeg;base64,' + imageData;
          }

          // 设置视频源和当前帧数据
          this.videoSrc = src;
          this.currentVideoFrame = src; // 保存当前帧，用于拍照

          // 第一次收到视频帧时，关闭加载状态
          if (this.isVideoLoading) {
            this.isVideoLoading = false;
          }
        }
      } catch (error) {
        console.warn('处理图像数据失败:', error);
      }
    },

    // 新增：关闭SSE连接方法
    closeSSEConnection() {
      if (this.sseConnection) {
        try {
          // 通知后端关闭视频流
          request({
            url: '/baiduFace/stopVideoStream',
            method: 'get'
          }).catch(error => {
            console.error('停止视频流请求失败:', error);
          });
        } catch (error) {
          console.error('发送停止视频流请求失败:', error);
        }

        // 关闭SSE连接
        try {
          this.sseConnection.close();
          this.sseConnection = null;
          console.log('SSE连接已关闭');
        } catch (error) {
          console.error('关闭SSE连接失败:', error);
        }
      }
    },

    // 修复后的确认拍照方法
    confirmCapture() {
      if (!this.currentVideoFrame) {
        this.$message.error('当前没有可用的视频帧');
        return;
      }

      try {
        // 使用当前视频帧作为拍照结果
        this.addList.photoData = this.currentVideoFrame;

        // 将图片数据转换为canvas，以便后续上传使用
        this.convertImageToCanvas(this.currentVideoFrame).then((canvas) => {
          // 重要：保存canvas引用，确保后续能够访问
          this.capturedCanvas = canvas;

          // 可选：创建预览图片用于用户确认
          const previewDataUrl = canvas.toDataURL('image/jpeg', 0.8);
          this.previewSrc = previewDataUrl;

          this.$message.success('拍照成功');
          this.closeCameraDialog();
        }).catch(error => {
          console.error('转换图片失败:', error);
          this.$message.error('图片处理失败，请重试');
        });

      } catch (error) {
        console.error('拍照失败:', error);
        this.$message.error('拍照失败，请重试');
      }
    },

    // 修复后的将图片转换为canvas的方法
    convertImageToCanvas(imageDataUrl) {
      return new Promise((resolve, reject) => {
        const img = new Image();
        img.onload = () => {
          try {
            // 获取或创建canvas元素
            let canvas = this.$refs.canvas;
            if (!canvas) {
              canvas = document.createElement('canvas');
              canvas.style.display = 'none';
              canvas.ref = 'canvas'; // 添加ref属性
              this.$el.appendChild(canvas);

              // 重要：手动更新 $refs
              this.$refs.canvas = canvas;
            }

            const context = canvas.getContext('2d');

            // 设置canvas尺寸
            canvas.width = img.width;
            canvas.height = img.height;

            // 清空canvas（重要！）
            context.clearRect(0, 0, canvas.width, canvas.height);

            // 将图片绘制到canvas上
            context.drawImage(img, 0, 0, canvas.width, canvas.height);

            console.log('图片已转换为canvas', canvas.width, canvas.height);

            // 验证canvas内容不为空
            const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
            const isBlank = imageData.data.every(pixel => pixel === 0);

            if (isBlank) {
              reject(new Error('Canvas内容为空'));
            } else {
              // 输出canvas内容用于调试
              console.log('Canvas内容验证通过，数据URL:', canvas.toDataURL('image/jpeg', 0.8).substring(0, 100) + '...');
              resolve(canvas);
            }
          } catch (error) {
            console.error('转换图片到canvas失败:', error);
            reject(error);
          }
        };

        img.onerror = (error) => {
          console.error('加载图片失败:', error);
          reject(error);
        };

        // 确保图片数据有效
        if (!imageDataUrl || !imageDataUrl.startsWith('data:image')) {
          reject(new Error('无效的图片数据'));
          return;
        }

        // 设置跨域属性（如果需要）
        img.crossOrigin = 'anonymous';
        img.src = imageDataUrl;
      });
    },

    // 新增：处理视频错误
    handleVideoError(error) {
      console.warn('视频帧显示错误:', error);
      // 可以在这里添加错误处理逻辑，比如重新连接
    },

    // 修改后的关闭摄像头对话框方法
    closeCameraDialog() {
      // 关闭SSE连接
      this.closeSSEConnection();

      // 重置状态
      this.videoSrc = '';
      this.currentVideoFrame = null;
      this.previewSrc = null;
      this.isVideoLoading = false;

      // 关闭对话框
      this.cameraDialogVisible = false;
    },

    // 重新拍照（保留原有方法以防需要）
    retryCapture() {
      this.previewSrc = null;
      // 不需要重新打开摄像头，因为视频流是持续的
    }
  },

  // 在组件销毁前关闭连接
  beforeDestroy() {
    this.closeSSEConnection();
    // 清理canvas引用
    this.capturedCanvas = null;
  }
}
</script>

<style scoped lang="scss">
.el-row {
  text-align: center;
}

::v-deep .el-input--small .el-input__inner {
  height: 48px;
  line-height: 48px;
  font-size: 18px;
}

::v-deep .el-form-item__label {
  font-size: 18px;
  color: #fff;
  line-height: 48px;
  font-weight: normal;
  padding-left: 20px;
  text-align-last: justify;
}

::v-deep .password {
  .el-form-item__label {
    text-align-last: auto;
    letter-spacing: 10px;
  }
}

.dialog-btn {
  margin-top: 10px;
  font-size: 18px;
  height: 40px;
}

// 提示弹窗样式
::v-deep .prompt-dialog {
  margin-top: 30vh !important;
  .el-dialog__body {
    height: 200px;
    text-align: center;
    font-size: 20px;
    color: #fff;
    padding-top: 54px;
    line-height: 36px;
  }
}

.photo {
  .el-form-item__label {
    display: inline-block;
    margin-right: 10px;
  }

  .el-button {
    margin-right: 10px;
  }
}

.el-dialog__body {
  text-align: center;
}

/* 新增：视频容器样式 */
.video-container {
  position: relative;
  width: 100%;
  height: 0;
  padding-bottom: 56.25%; /* 16:9 比例 */
  overflow: hidden;
  background-color: #000;
  margin-bottom: 15px;
  border-radius: 4px;
}

/* 视频帧样式 */
.video-frame {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background-color: transparent;
}

/* 加载指示器样式 */
.loading-indicator {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 300px;
  color: #666;
  font-size: 18px;

  i {
    font-size: 36px;
    margin-bottom: 15px;
    color: #409EFF;
    animation: rotate 2s linear infinite;
  }
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

/* 无视频流时的占位符样式 */
.no-video-placeholder {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background-color: #f5f5f5;
  color: #999;

  i {
    font-size: 64px;
    margin-bottom: 20px;
    color: #ccc;
  }

  p {
    font-size: 16px;
    margin: 0;
  }
}

/* 摄像头控制按钮样式 */
.camera-controls {
  display: flex;
  justify-content: center;
  gap: 15px;
  margin-top: 20px;

  .el-button {
    min-width: 100px;
  }
}

/* 对话框内容调整 */
::v-deep .el-dialog__body {
  padding: 20px;

  .video-container + .camera-controls {
    margin-top: 20px;
  }
}

/* 响应式调整 */
@media (max-width: 768px) {
  .video-container {
    padding-bottom: 75%; /* 4:3 比例，适合小屏幕 */
  }

  .camera-controls {
    flex-direction: column;
    align-items: center;

    .el-button {
      width: 150px;
      margin: 5px 0;
    }
  }
}
</style>
